sign = (v) ->
    if v == 0 
      return 0
    
    if v < 0 
      return -1
    
    return 1

calculateSlide = (tiles, e, x0, y0, x1, y1) ->
  dx = x1 - x0
  dy = y1 - y0

  sx = sign dx
  sy = sign dy

  touched = {}
  standedOn = {}

  for t in tiles.intersectNonSolid x0, y0, e
    standedOn[t] = true
    t.standingOn e

  while true
    moved = false
    if x0 != x1 and sx != 0
      col = tiles.intersectSolid x0 + sx, y0, e

      for v in col
        continue if touched[v] == true
        v.touched e
        touched[v] = true
      
      if col.length == 0
        x0 += sx 
        moved = true

    if y0 != y1 and sy != 0
      col = tiles.intersectSolid x0, y0 + sy, e
      
      for v in col
        continue if touched[v] == true
        v.touched e
        touched[v] = true

      if col.length == 0
        y0 += sy
        moved = true

    if moved
      for t in tiles.intersectNonSolid x0, y0, e
        continue if standedOn[t] == true
        standedOn[t] = true
        t.standingOn e
    
    if not moved
      return [x0, y0]
    


calculateDeflection = (t, x, y, w, h, dx, dy) ->
    b1 = 
      x : x
      y : y
      w : w
      h : h
      vx : dx
      vy : dy

    sp = [x, y, dx, dy]
    tmin = 1000000000
    
    for tile in t
      b2 =
        x : tile.x
        y : tile.y
        w : 64
        h : 64

      col = window.physics.sweptAABB b1, b2

      if col.t < tmin
        sp[0] = x + dx * col.t
        sp[1] = y + dy * col.t

        if col.t == 1.0
          continue

        remainingtime = 1.0 - col.t
        
        vx = dx
        vy = dy

        vx *= remainingtime
        vy *= remainingtime

        if (Math.abs(col.nx) > 0.0001)
          vx = -vx;
        if (Math.abs(col.ny) > 0.0001)
          vy = -vy;

        sp[2] = vx
        sp[3] = vy

    return sp


aabbIntersect = (a, b) ->
  return (Math.abs(a.x - b.x) * 2 < (a.w + b.w)) && (Math.abs(a.y - b.y) * 2 < (a.h + b.h))


sweptAABB = (b1, b2) ->

  return {t : 0.0, nx : 0, ny : 0} if aabbIntersect b1, b2 

  xInvEntry = yInvEntry = xInvExit = yInvExit = 0.0
  xEntry = yEntry = xExit = yExit = 0.0

  if b1.vx > 0.0
    xInvEntry = b2.x - (b1.x + b1.w)
    xInvExit = (b2.x + b2.w) - b1.x
  else 
    xInvEntry = (b2.x + b2.w) - b1.x
    xInvExit = b2.x - (b1.x + b1.w)


  if b1.vy > 0.0
    yInvEntry = b2.y - (b1.y + b1.h)
    yInvExit = (b2.y + b2.h) - b1.y
  else
    yInvEntry = (b2.y + b2.h) - b1.y
    yInvExit = b2.y - (b1.y + b1.h)
  

  if b1.vx == 0.0
    xEntry = -Infinity
    xExit = Infinity
  else
    xEntry = xInvEntry / b1.vx
    xExit = xInvExit / b1.vx

  if b1.vy == 0.0
    yEntry = -Infinity
    yExit = Infinity
  else
    yEntry = yInvEntry / b1.vy
    yExit = yInvExit / b1.vy
  
  if yEntry > 1.0 
    yEntry = -Infinity
  
  if xEntry > 1.0
    xEntry = -Infinity


  entryTime = Math.max xEntry, yEntry
  exitTime = Math.min xExit, yExit

  return {t : 1} if xEntry > exitTime
  return {t : 1} if xEntry < 0.0 && yEntry < 0.0
  return {t : 1} if xEntry < 0.0 && (b1.x + b1.w < b2.x || b1.x > b2.x + b2.w)
  
  return {t : 1} if yEntry < 0.0 && (b1.y + b1.h < b2.y || b1.y > b2.y + b2.h)


  normalx = 0
  normaly = 0
  if xEntry > yEntry
    if xInvEntry < 0.0
      normalx = 1.0
      normaly = 0.0
    else
      normalx = -1.0
      normaly = 0.0
  else
    if yInvEntry < 0.0
      normalx = 0.0
      normaly = 1.0
    else
      normalx = 0.0
      normaly = -1.0
  return {
    nx : normalx * sign b1.vx
    ny : normaly * sign b1.vy
    t : entryTime
  }

line = (x0, y0, x1, y1, fn) ->
  x0 |= 0
  y0 |= 0
  x1 |= 0
  y1 |= 0
  dx = Math.abs(x1 - x0)
  dy = Math.abs(y1 - y0)
  sx = if (x0 < x1) then 1 else -1
  sy = if (y0 < y1) then 1 else -1
  err = dx - dy

  while true
    return true if fn(x0, y0) == true
    return false if x0 == x1 && y0 == y1

    e2 = 2 * err;
    
    if (e2 >-dy)
      err -= dy
      x0  += sx

    if (e2 < dx)
      err += dx
      y0  += sy

window.physics = 
  sweptAABB      : sweptAABB
  line      : line
  calculateSlide : calculateSlide
  calculateDeflection : calculateDeflection
  sign : sign
  dist : (a, b) ->
    dx = a.x - b.x
    dy = a.y - b.y
    return Math.sqrt(dx * dx + dy * dy)